home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
9-Digit Zip Code Directory
/
9-Digit Zip Code Directory (American Business Information) (ABIZIP-12).ISO
/
z4src.zip
/
CLLIST.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-11
|
21KB
|
680 lines
//----------------------------------------------------------------------------
// MODULE DESCRIPTION
//
// Module: cllist.cpp
// Title: C++ Class Libraries
// Notice: John M. Weeder
// Copyright (c) 1993. All rights reserved.
// This module contains proprietary information and should be
// treated as confidential.
//
//----------------------------------------------------------------------------
// MAINTENANCE HISTORY
//
// $Workfile$
// $Revision$
// $Author$
// $Date$
// $Log$
//
//----------------------------------------------------------------------------
// MODULE NARRATIVE
//
// This module contains code for the class CL_LIST.
//
// The code in this module may be written in C++ or C.
//
// This module is portable to:
// DOS 3.X+
// MS Windows 3.X+
// OS/2 2.X+
// OS/2 2.0 PM
//
// The following compilers are supported:
// MSC 6.0A
// MSC/C++ 7.0
// Borland C++ 3.1 for DOS
// Borland C++ 1.0 for OS/2 2.X
//
//----------------------------------------------------------------------------
#include <class.hpp>
//----------------------------------------------------------------------------
// Description: Default constructor
// Parameters: _pfnlistcomp List compare function
// Returns:
//----------------------------------------------------------------------------
FN_M CL_LIST::CL_LIST(PFNLISTCOMP _pfnlistcomp)
{
CL_LIST::Initialize(CL_INIT_CLASS);
pfnlistcomp = _pfnlistcomp;
}
//----------------------------------------------------------------------------
// Description: Copy constructor
// Parameters: rccl_list Reference to object to copy.
// Returns:
//----------------------------------------------------------------------------
FN_M CL_LIST::CL_LIST(RCCL_LIST rccl_list)
{
CL_LIST::Initialize(CL_INIT_CLASS);
*this = rccl_list;
}
//----------------------------------------------------------------------------
// Description: Destructor
// Parameters:
// Returns:
//----------------------------------------------------------------------------
FN_M CL_LIST::~CL_LIST()
{
CL_LIST::Destroy(FALSE);
}
//----------------------------------------------------------------------------
// Description: Delete an element from a list
// Parameters: pcl_element Element to add.
// pelemAfter Element to insert after.
// Ignored if list is sorted.
// If NULL, insert at start of list.
// Default is NULL.
// Returns:
//----------------------------------------------------------------------------
VOID FN_M CL_LIST::Add(PCL_ELEMENT pcl_element, PCL_ELEMENT pelemAfter)
{
Assert(pcl_element && pcl_element != pelemAfter);
Assert(pelemAfter == NULL || Index(pelemAfter) >= 0);
if (pcl_element->InList()) // Delete from current list
pcl_element->List()->Delete(pcl_element);
if (pfnlistcomp) // If sorted list, search for
{ // place to insert element into list
pelemAfter = pelemFirst;
if (pfnlistcomp(pelemAfter, pcl_element) > 0)
pelemAfter = NULL;
if (pelemAfter)
{
while (pelemAfter->pelemNext
&& (*pfnlistcomp)(pelemAfter->pelemNext, pcl_element) < 0)
{
pelemAfter = pelemAfter->pelemNext;
}
}
}
if (pelemAfter == NULL || pelemFirst == NULL)
{
if (pelemFirst) // Link to first element
pelemFirst->pelemPrev = pcl_element;
pcl_element->pelemNext = pelemFirst;
pelemFirst = pcl_element; // Point to new head of list
if (pelemLast == NULL) // If only element, point tail to it
pelemLast = pcl_element;
if (pelemCur == NULL) // If no current element, set
pelemCur = First(); // to first element
}
else // Insert in the middle or end of the
{ // list
pcl_element->pelemNext = pelemAfter->pelemNext;
pcl_element->pelemPrev = pelemAfter;
pelemAfter->pelemNext = pcl_element;
if (pcl_element->pelemNext)
pcl_element->pelemNext->pelemPrev = pcl_element;
else
pelemLast = pcl_element;
}
pcl_element->plist = this;
cElems++;
return ;
}
//----------------------------------------------------------------------------
// Description: Delete an element from a list
// Parameters: pcl_element Element to delete
// If NULL, return offset of current element.
// Default is NULL.
// Returns:
//----------------------------------------------------------------------------
VOID FN_M CL_LIST::Delete(PCL_ELEMENT pcl_element)
{
if (pcl_element == NULL)
pcl_element = Current();
if (pcl_element == NULL)
return ;
Assert(Index(pcl_element) >= 0);
// Remove from list
if (pcl_element->pelemNext)
pcl_element->pelemNext->pelemPrev = pcl_element->pelemPrev;
if (pcl_element->pelemPrev)
pcl_element->pelemPrev->pelemNext = pcl_element->pelemNext;
// Adjust list
if (pelemFirst == pcl_element)
pelemFirst = pcl_element->pelemNext;
if (pelemLast == pcl_element)
pelemLast = pcl_element->pelemPrev;
if (pelemCur == pcl_element)
pelemCur = NULL;
cElems--;
// Reset element
pcl_element->pelemPrev = pcl_element->pelemNext = NULL;
pcl_element->plist = NULL;
return;
}
//----------------------------------------------------------------------------
// Description: Destroy object. Free any resources used by object.
// Normally called by destructor.
// Should allow multiple calls from various classes.
// Parameters: fDestroyAll Destroy parents also?
// Default is TRUE.
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
BOOL FN_M CL_LIST::Destroy(BOOL fDestroyAll)
{
PCL_ELEMENT pelem;
SetCurrent();
while ((pelem = Current()) != NULL)
{
Next();
Delete(pelem);
delete pelem;
}
CL_LIST::Initialize(CL_INIT_CLASS_VARS);
if (fDestroyAll) // Destroy parent.
CL_LIST_PARENT::Destroy(fDestroyAll);
return TRUE;
}
//----------------------------------------------------------------------------
// Description: Search for a list element. A simple linear search is used.
// Only the first element is returned.
// Parameters: pfnlistfind Search function.
// pv Search key.
// Returns: Pointer to element or NULL.
//----------------------------------------------------------------------------
PCL_ELEMENT FN_M CL_LIST::Find(PFNLISTFIND pfnlistfind, PVOID pv)
{
Assert(pfnlistfind);
PCL_ELEMENT pelem = pelemFirst;
while (pelem && (*pfnlistfind)(pelem, pv) != 0)
pelem = pelem->pelemNext;
return pelem;
}
//----------------------------------------------------------------------------
// Description: Get element by index.
// Parameters: sIndex Index of element to return.
// Returns: Pointer to element or NULL.
//----------------------------------------------------------------------------
PCL_ELEMENT FN_M CL_LIST::Get(SIZET cIndex)
{
if (cIndex >= cElems)
return NULL;
PCL_ELEMENT pelem = pelemFirst;
for (;cIndex; cIndex--)
pelem = pelem->pelemNext;
return pelem;
}
//----------------------------------------------------------------------------
// Description: Return offset of element in list.
// Parameters: pcl_element Element to return offset of.
// If NULL, return offset of current element.
// Default is NULL.
// Returns: Offset from first element. 0..Count()-1
// -1 for error or element not found.
//----------------------------------------------------------------------------
SHORT FN_M CL_LIST::Index(PCL_ELEMENT pcl_element)
{
if (pcl_element == NULL)
pcl_element = Current();
if (pcl_element)
{
SHORT sIndex = 0; // Index of element
PCL_ELEMENT pelem = pelemFirst; // Search for element
while (pelem && pelem != pcl_element)
{
pelem = pelem->pelemNext;
sIndex++;
}
if (pelem) // Found it, return index
return sIndex;
}
return -1; // Not found
}
//----------------------------------------------------------------------------
// Description: Initialize object.
// Normally called by constructor.
// Should allow multiple calls from various classes.
// Parameters: sInit Initialization code. May be one of the following:
// CL_INIT_CLASS Reset class variables and
// and dynamic allocations for
// this class only.
// CL_INIT_CLASS_VARS Reset class variables for
// this class only.
// CL_INIT_VARS Reset class variables for
// this class only.
// CL_INIT_ALL Initialize class and all
// parent class, including
// dynamic memory allocation.
// Default is CL_INIT_ALL
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
BOOL FN_M CL_LIST::Initialize(SHORT sInit)
{
if (sInit == CL_INIT_VARS || sInit == CL_INIT_ALL)
CL_LIST_PARENT::Initialize(sInit);
pfnlistcomp = NULL;
pelemFirst = pelemLast = pelemCur = NULL;
cElems = 0;
return TRUE;
}
//----------------------------------------------------------------------------
// Description: Increment operator
// Parameters:
// Returns: Pointer to element or null
//----------------------------------------------------------------------------
PCL_ELEMENT FN_M CL_LIST::Next()
{
if (pelemCur)
pelemCur = pelemCur->pelemNext;
return pelemCur;
}
//----------------------------------------------------------------------------
// Description: Assignment operator
// NOTE: Don't copy object into self
// Parameters: rccl_list Reference to right value.
// Returns: Reference to new object.
//----------------------------------------------------------------------------
RCCL_LIST FN_M CL_LIST::operator=(RCCL_LIST rccl_list)
{
if (this != &rccl_list)
{
Invalid("CL_LIST::operator=");
}
return (RCCL_LIST)*this;
}
//----------------------------------------------------------------------------
// Description: Add element to list
// Parameters: pCL_ELEMENT Element to add.
// Returns: Reference to new object.
//----------------------------------------------------------------------------
RCL_LIST FN_M CL_LIST::operator+=(PCL_ELEMENT pcl_element)
{
Add(pcl_element);
return *this;
}
//----------------------------------------------------------------------------
// Description: Delete element from list
// Parameters: pcl_element Element to delete.
// Returns: Reference to new object.
//----------------------------------------------------------------------------
RCL_LIST FN_M CL_LIST::operator-=(PCL_ELEMENT pcl_element)
{
Assert(pcl_element);
Delete(pcl_element);
return *this;
}
//----------------------------------------------------------------------------
// Description: Return element at a particular offset
// Parameters:
// Returns: Pointer to element or null
//----------------------------------------------------------------------------
PCL_ELEMENT FN_M CL_LIST::operator[](SHORT sIndex)
{
return Get(sIndex);
}
//----------------------------------------------------------------------------
// Description: Increment operator - prefix.
// Parameters:
// Returns: Pointer to element or null
//----------------------------------------------------------------------------
PCL_ELEMENT FN_M CL_LIST::operator++()
{
if (pelemCur)
pelemCur = pelemCur->pelemNext;
return pelemCur;
}
//----------------------------------------------------------------------------
// Description: Increment operator - postfix.
// Parameters:
// Returns: Pointer to element or null
//----------------------------------------------------------------------------
PCL_ELEMENT FN_M CL_LIST::operator++(int)
{
if (pelemCur)
pelemCur = pelemCur->pelemNext;
return pelemCur;
}
//----------------------------------------------------------------------------
// Description: Decrement operator - prefix.
// Parameters:
// Returns: Pointer to element or null
//----------------------------------------------------------------------------
PCL_ELEMENT FN_M CL_LIST::operator--()
{
if (pelemCur)
pelemCur = pelemCur->pelemPrev;
return pelemCur;
}
//----------------------------------------------------------------------------
// Description: Decrement operator - postfix.
// Parameters:
// Returns: Pointer to element or null
//----------------------------------------------------------------------------
PCL_ELEMENT FN_M CL_LIST::operator--(int)
{
if (pelemCur)
pelemCur = pelemCur->pelemPrev;
return pelemCur;
}
//----------------------------------------------------------------------------
// Description: Decrement operator
// Parameters:
// Returns: Pointer to element or null
//----------------------------------------------------------------------------
PCL_ELEMENT FN_M CL_LIST::Previous()
{
if (pelemCur)
pelemCur = pelemCur->pelemPrev;
return pelemCur;
}
//----------------------------------------------------------------------------
// Description: Retrieve object from persistent storage
// Parameters: pcsz Name of object.
// pcszSub Sub-name of object.
// The first character of the name should be '~'.
// If NULL, no sub name is available.
// Default is NULL
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
BOOL FN_M CL_LIST::Retrieve(PCSZ pcsz, PCSZ pcszSub)
{
Assert(pcsz);
// Create sub-name for object
CL_STRING string("%s~CL_LIST", (pcszSub ? pcszSub: ""));
if (string.IsError())
return FALSE;
// Get parent
if (!CL_LIST_PARENT::Retrieve(pcsz, (PCSZ)string))
return FALSE;
return !IsError();
}
//----------------------------------------------------------------------------
// Description: Return offset of element in list.
// Parameters: pcl_element Set current element.
// If NULL, make first element current.
// Default is NULL.
// Returns:
//----------------------------------------------------------------------------
PCL_ELEMENT FN_M CL_LIST::SetCurrent(PCL_ELEMENT pcl_element)
{
if (pcl_element == NULL)
pcl_element = First();
Assert(pcl_element == NULL || Index(pcl_element) >= 0);
pelemCur = pcl_element;
return pelemCur;
}
//----------------------------------------------------------------------------
// Description: Store object to persistent storage
// Parameters: pcsz Name of object.
// pcszSub Sub-name of object.
// The first character of the name should be '~'.
// If NULL, no sub name is available.
// Default is NULL
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
BOOL FN_M CL_LIST::Store(PCSZ pcsz, PCSZ pcszSub)
{
Assert(pcsz);
if (IsError()) // Check that object is valid
return FALSE;
// Create sub-name for object
CL_STRING string("%s~CL_LIST", (pcszSub ? pcszSub: ""));
if (string.IsError())
return FALSE;
// Store parent
if (!CL_LIST_PARENT::Store(pcsz, (PCSZ)string))
return FALSE;
return TRUE; // Done
}
//----------------------------------------------------------------------------
// Description: Print object value to debugging output.
// Parameters: pccl_list Pointer to dynamic object.
// If NULL, static data elements are printed.
// Default is NULL.
// pcsz Name of object.
// If NULL, no name is displayed.
// Default is NULL.
// cLevel Display level.
// Default is zero.
// Returns:
//----------------------------------------------------------------------------
#if COMPILE_DEBUG
VOID FN_M CL_LIST::Print(PCCL_LIST pccl_list, PCSZ pcsz, SIZET cLevel)
{
#if COMPILE_TEST
OutputL(cLevel, "CL_LIST%s%s", (pcsz?"::":""), (pcsz?pcsz:""));
cLevel++;
if (pccl_list)
{
Output(" <%p>\n", pccl_list);
if(!pccl_list->IsError())
{
OutputL(cLevel, "pfnlistcomp = %p\n", pccl_list->pfnlistcomp);
OutputL(cLevel, "pelemFirst = %p\n", pccl_list->pelemFirst );
OutputL(cLevel, "pelemLast = %p\n", pccl_list->pelemLast );
OutputL(cLevel, "pelemCur = %p\n", pccl_list->pelemCur );
OutputL(cLevel, "cElems = %u\n", pccl_list->cElems );
}
}
else
Output(" <NULL>\n");
CL_LIST_PARENT::Print((CL_LIST_PARENT _FAR_ *)pccl_list, pcsz, cLevel);
return ;
#else
NOTUSED(cLevel);
NOTUSED(pccl_list);
NOTUSED(pcsz);
return ;
#endif
}
#endif
//----------------------------------------------------------------------------
// Test class
//----------------------------------------------------------------------------
#if COMPILE_TEST
CLASSDEF(CL_LISTTEST);
class CLASSTYPE CL_LISTTEST : public CL_ELEMENT
{
CHAR szValue[20];
public:
CL_LISTTEST(PSZ psz)
{
strcpy(szValue, psz);
}
VOID FN_M Print()
{
Output("%s\n", szValue);
}
static SHORT FN_M Comp(PCCL_ELEMENT, PCCL_ELEMENT);
static SHORT FN_M Find(PCCL_ELEMENT, PVOID);
};
#endif
//----------------------------------------------------------------------------
// Description: Test function to sort a list alphabetically.
// Parameters: pelem1, pelem2 Elements to compare
// Returns: < 0 Element 1 < element 2
// == 0 Element 1 == element 2
// > 0 Element 1 > element 2
//----------------------------------------------------------------------------
#if COMPILE_TEST
SHORT FN_M CL_LISTTEST::Comp(PCCL_ELEMENT pelem1, PCCL_ELEMENT pelem2)
{
PCL_LISTTEST plisttest1 = (PCL_LISTTEST)pelem1;
PCL_LISTTEST plisttest2 = (PCL_LISTTEST)pelem2;
return (SHORT)strcmp(plisttest1->szValue,plisttest2->szValue);
}
#endif
//----------------------------------------------------------------------------
// Description: Test function to find a member of a list.
// Parameters: pelem Element to compare
// pv Data to compare to.
// Returns: != 0 Element is not a match
// == 0 Element matches
//----------------------------------------------------------------------------
#if COMPILE_TEST
SHORT FN_M CL_LISTTEST::Find(PCCL_ELEMENT pelem, PVOID pv)
{
PCL_LISTTEST plisttest = (PCL_LISTTEST)pelem;
return (SHORT)strcmp(plisttest->szValue,(PCSZ)pv);
}
#endif
//----------------------------------------------------------------------------
// Description: Run standard test suite on object.
// Parameters: sTest Test to run.
// If 0, run default tests.
// Default is 0.
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
#if COMPILE_DEBUG
BOOL FN_M CL_LIST::Test(SHORT sTest)
{
#if COMPILE_TEST
if (sTest == 1) // Test 1 is always a test of storage
{
CL_LIST cl_list;
cl_list.Store("CL_LIST");
cl_list.Retrieve("CL_LIST");
CL_LIST::Print(&cl_list);
}
CL_LIST list(CL_LISTTEST::Comp);
CL_LISTTEST elem1((PSZ)"aaaaa");
CL_LISTTEST elem2((PSZ)"bbbbb");
CL_LISTTEST elem3((PSZ)"ccccc");
CL_LISTTEST elem4((PSZ)"ddddd");
PCL_LISTTEST pelem;
list.Add(&elem4);
list.Add(&elem1);
list += &elem3;
list.Add(&elem2);
list -= &elem3;
list.Add(&elem4); // Add it again
list += &elem3;
Print(&list);
pelem = (PCL_LISTTEST)list.Find(CL_LISTTEST::Find, "ccccc");
if (pelem)
pelem->Print();
else
return FALSE;
list.SetCurrent();
do
{
pelem = (PCL_LISTTEST)list.Current();
if (pelem)
pelem->Print();
else
return FALSE;
}
while (list++);
for (SHORT i = 0; i < list.Count(); ++i)
{
pelem = (PCL_LISTTEST)list[i];
if (pelem)
pelem->Print();
else
return FALSE;
}
return TRUE;
#else
NOTUSED(sTest);
return TRUE;
#endif
}
#endif
//----------------------------------------------------------------------------
//------------------------------- End of File --------------------------------
//----------------------------------------------------------------------------